package com.crime.crimemonitorclient;

import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Random;

import android.os.AsyncTask;

public class CrimeObservationsAsyncLoadingTask
	extends AsyncTask<Void, Void, CrimeTimeSeriesObservation[]>
{
	private final OnCrimeObservationsLoadedListener mObservationsLoadedListener;
	private final URL mServiceURL;
	private Exception mException;
	private long mMinTime;
	private long mMaxTime;
	private TimeGranularity mTimeGranularity;
	
	public CrimeObservationsAsyncLoadingTask(
			final long minTime, final long maxTime,
			final TimeGranularity timeGranularity,
			final OnCrimeObservationsLoadedListener observationsLoadedListener,
			final URL serviceURL)
	{
		if(observationsLoadedListener == null)
			throw new NullPointerException("Argument 'observationsLoadedListener' cannot be null.");
		
		if(serviceURL == null)
			throw new NullPointerException("Argument 'serviceURL' cannot be null.");
		
		this.mObservationsLoadedListener = observationsLoadedListener;
		this.mServiceURL = serviceURL;
		this.mMinTime = minTime;
		this.mMaxTime = maxTime;
		this.mTimeGranularity = timeGranularity;
	}

	@Override
	protected CrimeTimeSeriesObservation[] doInBackground(Void... params)
	{
		try {
			Thread.sleep(1000);
			
			// create a sequence of observations
			int calendarField = Calendar.YEAR;
			Calendar start = Calendar.getInstance();
			Calendar end = Calendar.getInstance();
			
			start.setTimeInMillis(this.mMinTime);
			end.setTimeInMillis(this.mMaxTime);
			
			switch(this.mTimeGranularity)
			{
				case Year:
				{
					calendarField = Calendar.YEAR;
					
					start.clear(Calendar.MONTH);

					start.clear(Calendar.WEEK_OF_MONTH);
					start.clear(Calendar.WEEK_OF_YEAR);
					
					start.clear(Calendar.DAY_OF_MONTH);
					start.clear(Calendar.DAY_OF_YEAR);
					start.clear(Calendar.DAY_OF_WEEK);
					start.clear(Calendar.DAY_OF_WEEK_IN_MONTH);
					
					start.clear(Calendar.HOUR);
					start.clear(Calendar.HOUR_OF_DAY);
					
					start.clear(Calendar.MINUTE);
					start.clear(Calendar.SECOND);
					start.clear(Calendar.MILLISECOND);
					
					break;
				}
				
				case Month:
				{
					calendarField = Calendar.MONTH;
					
					start.clear(Calendar.WEEK_OF_MONTH);
					start.clear(Calendar.WEEK_OF_YEAR);
					
					start.clear(Calendar.DAY_OF_MONTH);
					start.clear(Calendar.DAY_OF_YEAR);
					start.clear(Calendar.DAY_OF_WEEK);
					start.clear(Calendar.DAY_OF_WEEK_IN_MONTH);
					
					start.clear(Calendar.HOUR);
					start.clear(Calendar.HOUR_OF_DAY);
					
					start.clear(Calendar.MINUTE);
					start.clear(Calendar.SECOND);
					start.clear(Calendar.MILLISECOND);
					break;
				}
				
				case Day:
				{
					calendarField = Calendar.DAY_OF_YEAR;
					
					start.clear(Calendar.HOUR);
					start.clear(Calendar.HOUR_OF_DAY);
					
					start.clear(Calendar.MINUTE);
					start.clear(Calendar.SECOND);
					start.clear(Calendar.MILLISECOND);
					
					break;
				}
				
				case Hour:
				{
					calendarField = Calendar.HOUR_OF_DAY;
					
					start.clear(Calendar.MINUTE);
					start.clear(Calendar.SECOND);
					start.clear(Calendar.MILLISECOND);
					
					break;
				}
			}
			
			Random obsValueRand = new Random();
			final int MAX_CRIMES = 100;
			List<CrimeTimeSeriesObservation> observations = new ArrayList<CrimeTimeSeriesObservation>();
			
			while(start.before(end))
			{
				long obsTime = start.getTimeInMillis();
				int obsValue = obsValueRand.nextInt(MAX_CRIMES);
				
				observations.add(
						new CrimeTimeSeriesObservation(obsTime, obsValue));
				
				//String dateString = new SimpleDateFormat("yyyy.MM.dd H:m:s").format(start.getTime());
				
				start.add(calendarField, 1);
			}
			
			return observations.toArray(new CrimeTimeSeriesObservation[0]);
		}
		catch (Exception e)
		{
			this.mException = e;
			return null;
		}
	}
	
	@Override
	protected void onPostExecute(CrimeTimeSeriesObservation[] result) {
		// TODO: pass the exception to the client or at least announce its existence somehow
		if(this.mException == null)
		{
			// call the listener
			this.mObservationsLoadedListener.onCrimeObservationsLoaded(result, this.mMinTime, this.mMaxTime);
		}
	}
}
